Copyright (c) 1999 Massachusetts Institute of Technology

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, see https://gnu.org/licenses or write
to:
  Free Software Foundation, Inc.
  51 Franklin Street, Fifth Floor
  Boston, MA 02110-1301
  USA
------------------------------

JOBS IN ITS


@. ABSTRACT.

In ITS, a "job" is an entity that consists mainly of memory to hold
a program, registers to run it with, and I/O channels for it to do
I/O on through the system.  Whenever a program is
running, it must be running "in" some job.  Jobs are structured
into trees;  the root of a tree is a "top-level" job, and for any
job, the job one step closer to the root is the first job's superior;
the first job is one of its inferiors.  Normally, each user has
one tree of jobs, but he may also have a few other secondary trees.

Jobs may read anything associated with any job, but usually may write
only their direct inferiors.

TABLE OF CONTENTS

A. OVERVIEW OF JOBS.

B. CREATING AND DELETING INFERIORS, AND OTHER METHODS OF CHANGING THE
   0. OPENING THE USR: DEVICE - A BASIC TOOL.
   1. CREATION
   2. DELETION
   3. DISOWNING
   4. REOWNING
   5. DETACHING
   6. ATTACHING
   7. LOGGING IN
   8. LOGGING OUT AND GUNNING

C. CONTROL OF INFERIORS.
   1. READING AND WRITING
   2. SHARING MEMORY BETWEEN JOBS
   3. LOADING
      a. Resetting
   4. DUMPING
      a. Pure dumping
      b. Impure dumping
   5. STARTING AND STOPPING
   6. HANDLING INTERRUPTS
   7. DEBUGGING CONTROLS.
   8. TTY PASSING

D. SYSTEM JOBS AND WHAT THEY DO
   1. THE SYSTEM JOB.
   2. THE CORE JOB.
   3. DEMON JOBS.

A. OVERVIEW OF JOBS.

Each ITS job has an address space, the slots of which may be filled
with various types of memory, perhaps shared with other jobs;  its own
set of accumulators (copied temporarily into the real ones when the
job is running);  a program counter (PC);  sixteen I/O channels, each of
which may be used to handle a device or file;  system "user variables"
with which the program in the job may communicate with the system;
and other variables used by the system in scheduling
or swapping the job, or as temporaries for system call routines.

The word "user" has two meanings on ITS: one is the human or other being
using a terminal;  the other is an individual "user job".  In specific
contexts either "job" or "user" sounds better for their common meaning.
A "program", however, is a more abstract entity;  the same program may
be running in several jobs (but using different files, etc. in each).

Each job is identified by two names, the UNAME and the JNAME, each of
which is up to six SIXBIT characters, left justified in a PDP-10 word.
They are available in the .UNAME and .JNAME user variables of the job.
These two names uniquely identify the job.
All the jobs in a tree must have the same uname.  Two trees may have
the same uname;  that usually means that they really correspond to the
same user.

Each job is also uniquely identified by its "job number" (or
"user number"), which is a small positive number.  This number
is the usual way to specify a job in a system call.  A job may find
out its own number by reading its .UIND user variable;  its superior's
is in its own .SUPPRO user variable.  The term "user index"
may mean, loosely, the job number, but more strictly it means the
job number times LUBLK, the length of the system's per-job data block
(the "user variable block").  Supported communications paths
between the user and the system use the job number, not the user index
itself, even if the term "user index" is used.

A job has several "user variables" which are really variables in the
system that pertain to it, and are readable by that job or others
using the .USET and .SUSET UUO's (see ITS UUOS).  Each user variable
has a name, which starts with ".".  User variables can be opened in
DDT just like memory locations, although what DDT does to access them
is a .USET.  Some user variables, such as .UIND, .SUPPRO, .UNAME and
.JNAME mentioned above, exist solely to be read by programs.  Others
also allow the program to tell the system how to treat it;  examples
are .OPTION, which contains bits that enable various system features,
and .MASK, which is used to enable user interrupts (see ITS INTRUP).
A complete list of user variables and what they contain is in the
file ITS USETS.

When a user connects to ITS by typing ^Z or CALL on a terminal, he is
supplied with a single top-level job using that terminal, running the
program "DDT" (on DM, "MONIT" is used instead).  The jname of that
job is always "HACTRN" (pronounced "hack-tran"),
and the job is called "a HACTRN".  The uname
will be three backarrows followed by three digits, identifying the tree
as non-logged-in.  "Logging in" is nothing other than altering the uname
of the hactrn to a more meaningful name.  It makes little direct
difference.
DDT and MONIT both provide facilities for creating other jobs for the
user, loading programs into them, and running them.  There are no user
commands per se for controlling jobs built into ITS;  instead, the
user gives commands to DDT or MONIT telling them to execute the system
calls to control his other jobs.

The two main types of job trees are the console-controlled trees and
the non-console-controlled (or "disconsolate") trees.  A console
controlled tree has one terminal which is "in use as a console" by
the whole tree.  All the jobs in the tree can refer to that terminal as
device TTY:.  The number of that terminal can be found in the .CNSL
variable of any job of the tree.
At any time, only one of the jobs in the tree has
permission to do I/O to the console;  that job is said to "own"
the console.  Ownership is transferred by means of .ATTY and .DTTY
UUO's executed by jobs in the tree (see ITS TTY).  If ^Z (or CALL on
TV's) is typed on a console, the job that owns it gets a fatal
interrupt.  The jobs may also have other terminals open "as devices",
but those can be in use only by a single job, not the whole tree.
The console-controlled trees are usually the ones with hactrn's at the
top.

Disconsolate trees do not have any console, but in all other respects
bahave just like console-controlled trees.  They may or may not be
"disowned".  If they are, they get worse treatment from the scheduler
and swapper, and also may be more conveniently "reowned" (made into a
subtree of another tree - see below).  Usually only system demons and
job-device handlers are disconsolate non-disowned trees.
Job-devices will have a .CNSL equal to that of the tree of the
job using the job-device.  Other disconsolate jobs will have a .CNSL
of -1 if they are scheduled as part of the system, or -2 if scheduled
as disowned jobs.

Jobs often refer to each other using a device, the "USR" device.  A job
may be opened on the USR device by specifying its uname and jname as the
opened filenames.  It is then possible to examine or deposit the job's
memory or user variables, etc.  This is why DDT, when it starts up,
mentions its uname and jname by saying "USR:<uname> <jname>".
The USR device should not be confused
with the JOB device, which is a mechanism for creating software devices
which enables the system calls that manipulate the device to be
simulated and handled by a user program, the job-device handler program
(See ITS JOBDEV).

The remainder of this file is devoted to desribing the ITS system calls
with which jobs may create, delete, sense and control other jobs.

B. CREATING AND DELETING INFERIORS, AND OTHER METHODS OF CHANGING THE
  TREE STRUCTURE OF JOBS.

 0. OPENING THE USR: DEVICE - A BASIC TOOL.

Unfortunately, many different things are done by opening the
USR device in different ways in different situations.  They
include creation of inferiors, reowning disowned jobs, selection
of existing jobs (inferiors or not), and testing for the existence
of a job.  Opening USR is the ONLY way to do those things.  What's
more, a job's memory cannot be read or written without having a USR
channel open in the appropriate direction, and a job's user variables
cannot be read or written without at least one USR channel open in
either direction.  Thus, opening USR: is very important.  It is intended
that this mechanism will be made more rational in the future.

This section will describe what opening the USR device will do,
organised by how it is done.  Later sections will say what
to do to achieve a specific goal.

By convention, "USRI" and "USRO" are the canonical names in MIDAS
programs for the I/O channels used for opening the USR device for
input and output, respectively.  Their use in an inferior-handling
program is a sort of comment.

A USR: open always specifies two filenames.  Normally they are
the uname and jname of the job to be opened.  However, 0 may
be used as the first filename to specify your own uname.
If the second filename is 0, then the first is not really a
name but a job spec;  this crock makes it possible to open a
job known only by its number.

A USR: open must also ask for either block mode or unit mode.
Right now SIOT on unit mode USR channels is not as efficient as
IOT on block mode channels, so it is usually better to open in
block mode.  In any case, this choice is orthogonal to everything
else.

All USR: opens should specify image mode.  Ascii mode doesn't now
exist for the USR device, and if you ask for it you will get image
mode instead, so for compatibility with the future you should ask
for image mode.

There are four things specified in each USR open that affect the
actions taken in important ways.  They are the two filenames,
the direction, and the device-dependent bit 1.4 of the open-mode,
known here (and inside ITS) as UBPFJ.

If UBPFJ is set, the open may be for reading only, and will fail with
code 4 if the job specified by the uname and jname does not exist.
If the job does exist, it will be opened as a "foreign job", which
means that the opening job may not modify it at all using the
channel opened in this way.  Also, the process of opening the job
with UBPFJ is guaranteed not to alter it.  This style of open is
good for asking whether a job exists with particular names.

Without UBPFJ, if the open is for writing, then
if a job with the specified uname and jname exists and is the
  inferior of the job doing the open, it will be opened for
  writing, with no special side effects.
If a job with the specified names exists and can be reowned
  (it is a top-level disowned job), it will be reowned, and
  opened for writing.  Reowning may change its uname or jname,
  so whenever an open might reown a job the program should
  read back the uname and jname of the opened job just in case.
If no job with the specified names exists, then an attempt is
  made to create an inferior by that name.  If the specified
  uname isn't the same as yours, that is impossible, and the open
  fails with code 20.  If you already have the maximum number of
  inferiors, it fails with code 5.  If there are no job slots available,
  it fails with code 6.  If the attempt succeeds, the new inferior
  is opened for writing.
Otherwise (a job with the specified names exists, but isn't
  an inferior of the running job already and can't be made one
  by reowning it), the open fails with code 12.
Note that if an open for writing succeeds, you know the job that
is open is your inferior (thought it might not have been so before).

An open for reading, without UBPFJ, is like an open for writing
except that when the job exists but isn't an inferior and can't
be reowned, it will be opened as a foreign job (as if UBPFJ were 1).

To understand these possibilities better, think of the FOO$J command in
DDT, which means, essentially, "open the job named FOO".  That command
will reselect a job named FOO if there is one;  if not, it will create
one.  If there is a job named FOO that isn't a direct inferior of DDT,
it will be selected, but will be unwriteable (DDT will type a "#").  If
there is a disowned job named FOO, it will be reowned (made into an
inferior of DDT), and DDT will type ":$REOWNED$").

There is no easy way to tell after the fact what has happened when
an open without UBPFJ has succeeded.  You know you have an inferior,
if an open for writing succeeds,
but whether it is new, reowned or old is forgotten.  If you care,
you should find out in advance what is going to happen by doing
an open with UBPFJ set.  If it fails, you will get a newly created
inferior.  If it succeeds, look at the .APRC and .SUPPRO user variables.
If both are negative, you have a top-level disowned job which
would be reowned.  If .SUPPRO equals your .UIND variable, the
job is your inferior already.  Otherwise, an open for writing
would fail, and an open for reading would open it as a foreign job.

Some information is still available after an open.
The job's .UPC variable will be nonzero iff the job has ever run
(because the user-mode bit, %PCUSR, will be 1).
If the job has been run, then it certainly wasn't just created.
Also, if the job's uname or jname was changed by the open, then
it must have been reowned.

 1. CREATION

In order to create an inferior, one must choose a jname for it.
Its uname will have to be the same as its creator's, and together
the uname and jname must be unique among all jobs in existence.
An attempt to create an inferior looks just like an attempt to
open an existing job, so if the would-be creator is mistaken about
the uniqueness of the jname it may get confused (a way out of this
problem is described later).

Given a jname which isn't in use, an inferior of that name may be
created by simply opening the USR device with the uname and jname
as filenames, as in section 0.  You should open a channel in each
direction (call the input channel USRI and the output channel USRO).
If you are unwilling to try to live with a foreign job, do the
output open first.

One way to make sure of getting a newly created job is to check
in advance that the names are not in use, by opening them with
UBPFJ (see section 0) before actually trying to create the job.
If the test open succeeds, close the channel again and
pick a new jname.

The new inferior will have 1K of zeroed unshared core,
and will not be running (its .USTP will be nonzero).

Then, if you wish to handle interrupts from the inferior,
read the inferior's interrupt bit, which may be found in
the inferior's .INTB variable, and remember it somewhere.
That is the bit .IFPIR on which YOU will be interrupted,
if the inferior gets a fatal interrupt.

 2. DELETION

Inferiors do not need to remain open to continue to exist.  Simply
closing the channels one is open on does not delete it;  it is
merely hard to refer to until it is opened again.  This is so
that it is possible to have many inferiors without tying up many
I/O channels.  When it IS desired to delete an inferior, the
.UCLOSE uuo should be used:

	.UCLOSE <channel>,

This uuo kills the inferior open on <channel>.  All the channels
it is open on are closed.  The uuo does not skip.
If a foreign job instead of an inferior is open, all the channels
in this job that it is open on are closed, but it is not killed.
If there isn't a job open on the specified channel, an ILOPR
interrupt happens.

 3. DISOWNING

Disowning an inferior causes it to continue to exist, but no longer
as your inferior.  This can be useful for two reasons:
1) you wish to log out but want the inferior to remain, or
2) you want the job to become someone else's inferior.

Disowning is done with the DISOWN system call, as follows:

	.CALL [	SETZ ? 'DISOWN
		401000,,<job spec>]
	 .VALUE

It fails if the specified job isn't an inferior of the executing one.
If it succeeds, the specified job and its inferiors become
a separate disowned tree, of which the specified job is the top.
All channels on which the running job had that job open are closed.
See the DISOWN symbolic system call for more details and features.

 4. REOWNING

A top-level disowned job may be "reowned" (made one's inferior)
by opening it with bit 1.4 of the mode set to 0.  The uname of
every job in the reowned tree will be changed to equal that of
the reowning job, if necessary.  If as a result the uname/jname
pair of one of the reowned jobs is no longer unique, the jname
will be altered until the uname/jname pair is unique.

Another way to reown a job is to use the REOWN symbolic system
call.  The job to be reowned should already be open on an I/O
channel as a foreign user;  the REOWN will cause it to be open
as an inferior instead on the same channel.  An example is:

	.CALL [	SETZ ? SIXBIT/REOWN/ ? 401000,,USRI]
	 .VALUE

In DDT, selecting a job that may be reowned will always reown it.
DDT will type ":$REOWNED$" when that happens.  If the uname or
jname changes, DDT will type the new names.

 5. DETACHING

An entire tree may be made disowned, have its console taken
away from it, or both, with the DETACH system call.  The goal might
be to free the console for other use, or to make the tree into
a subtree of another tree by reowning it.

 6. ATTACHING

Attaching is the operation of connecting a terminal to a tree
as the tree's console.  The simplest kind of attachment takes
a free console and a disowned tree and connects them.  A top-level
console-controlled job may also attach one of its inferiors to
its console;  this has the same effect as if it were to disown
the inferior, detach itself, and then attach the erstwhile inferior
to the now free console, except that it happens more smoothly.
DDT's :ATTACH command uses the second flavor of ATTACH.  See the
ATTACH system call for more details.

 7. LOGGING IN

When the system creates a top-level job (such as a HACTRN), its uname
will be three "_"'s followed by three unique digits.  The job may
change its uname to one that gives more information to humans by
"logging in", which simply sets the uname.  The job must not have any
inferiors at the time;  the new uname must not start with "___" and
must not be in use.  A logged-in job may not log in again, but it may
change its uname with a .SUSET of .UNAME.
Logging in is done with the LOGIN symbolic system call, as follows:

	.CALL [	SETZ ? SIXBIT/LOGIN/
		SETZ [<new uname in sixbit>]]
	 .VALUE

The system call takes an optional third argument which now should be
used only by network server telnet jobs.  For them, its hould be the
sixbit string "HSTnnn", where nnn is the octal number of the foreign
host.

 8. LOGGING OUT AND GUNNING

A top-level job may delete itself, and all its inferiors, by "loggin
out".  This is done with the .LOGOUT UUO, as follows:

	.LOGOUT

The UUO returns only if it fails (the job isn't top level);  it does not
skip.  Programs that do not normally run in top-level jobs might
nevertheless be run in disowned jobs sometimes, so they should always
try to log out before requesting another command string or trying to ask
DDT to kill them.

A job may force any top-level job to log out by "gunning" it, using the
.GUN UUO.  The user index of the job to be gunned must be known.  The
way to do it is:

	MOVEI AC,<usr idx>
	.GUN AC,
	 JRST LOSE	;FAILED - JOB DIDN'T EXIST OR WASN'T TOP LEVEL.
	...		;SUCCEEDED.

Gunning should go on only between consenting adults.

C. CONTROL OF INFERIORS.

Jobs can control their inferiors by means of several special-purpose
system calls.  The more specific of them are documented below under
their uses.  One more general one is .USET, which allows the inferior's
"user variables" to be read or set.  For example, when section C.5.
speaks of "setting the job's .USTP variable", a .USET is meant.  The
way to set the .FOO variable with a .USET is this:
	.USET <channel>,[.SFOO,,[<new value>]]
Thus,	.USET <channel>,[.SUSTP,,[0]] will stop the job open on channel
<channel>.
	.USET <channel>,[.RFOO,,TEMP] will read the value of the .FOO
variable into TEMP.
For a complete description of the available .USET variables, and more
features of .USET, see the file ITS .USETS.

 1. READING AND WRITING

Reading or writing the contents of another job requires having the job
open on a USR device channel.  It is done by .IOT'ing on that channel;
thus, reading requires an input channel and output requires an output
channel.  Selection of the region to read or write is done by setting
the channel's access pointer with .ACCESS.  At the moment, SIOT on unit
mode USR channels is not very efficient, so it is best to open a job in
block mode.  That requires one extra instruction when transferring a
single word, which is a slight cost when compared with the ease of
transferring several words.
Note that ascii mode does not exist for the USR device - all channels
should be opened in image mode.

For example, to read the word at 500 into A, do

	.ACCESS USRI,[500]
	HRROI B,A
	.IOT USRI,B

assuming that USRI is the USR input channel.  This clobbers B.
To write A into the word at 500, do

	.ACCESS USRO,[500]
	HRROI B,A
	.IOT USRO,B

assuming that USRO is the USR output channel.  This clobbers B.

If a non-existent location in another job is read or written
with an IOT, an MPV interrupt results.  The .MPVA variable
of the job doing the reading will point at the non-existent
page of the other job.  (Actually, in ITS before version 1017,
when a non-existent page is written, the system may give an MPV,
or may do a .CORE on the inferior so that it has enough core
to make the IOT succeed.  ITS version 1017 and up will
always MPV).

 2. SHARING MEMORY BETWEEN JOBS

Another way to refer to the core of other jobs is to share
memory with them.  The slots of a job's page map should be
understood to be pointers to pages;  one page may be pointed
to independently by several slots in several jobs' page maps.
The CORBLK call can be used to copy other jobs' pointers to pages
into one's own job, resulting in shared memory.  Of course,
the memory will not have the same address in both slots
unless that is specificaly arranged for.
Unfortunately, other jobs' accumulators cannot be referred to
via memory sharing, since they are not stored anywhere in
the job's memory even when the job isn't running.

 3. LOADING

Loading a binary file into a job is not actually a fundamental
operation, since it could be done by a program that understood
the format of the binary file and deposited in appropriate
locations in the job being loaded.  However, for convenience'
sake, the LOAD system call exists for loading a binary file
into an inferior, or into the running job itself.  Both types
of ITS binary files may be loaded with LOAD;  it is not necessary
to know which type of file is being loaded.  Unfortunately, this
call works only for disk files.  For other devices, the program
must do it the hard way.  Code may be copied from DDT for that
purpose.

The LOAD system call takes two arguments:  the job to be loaded,
and the file to load.  The first is expressed by a job spec;  the
second, by a channel number.  For example,

	.CALL [	SETZ ? SIXBIT /LOAD/
		1000,,-1	;into myself
		401000,,DISKC]	;the file open on DISKC
	 .VALUE

The LOAD will leave the disk channel set up to read the file's
start instruction, which is a jump to the starting address, or
zero if there is no starting address.  After that word in the
file should come the symbol table and another copy of the start
instruction;  see DDT ORDER for their format.

Loading a PDUMP file (pure file) inserts pages into the job
as specified by the file.  It does not alter the pages of the
job that the file has no data for.  It also does not alter the
accumulators, even if page 0 is loaded.  Loading an SBLK file
(impure file) alters only the words of the job that the file
specifies data for.  The other words are NOT cleared.  If data
are specified in a nonexistent page, fresh memory will be
put there, and also in all nonexistent pages below it in the
address space!  Thus, if an impure dump is made of a job containing
nonzero data only at address 100000, the resulting file when
loaded will create core up through address 101777, even though
only the last page of that is actually being loaded.  This
unfortunately cannot be changed, but often causes trouble.  For
that reason (and many others), it is hoped that there will be
a new, more versatile binary format some day.

  a. Resetting

Loading per se modifies only the locations that the binary file
specifies data for.  It does NOT clear the rest of core.  If you
want to do that, chances are that you really want to RESET the
inferior.  To do that, use the .RESET UUO or the RESET symbolic system
call on an I/O channel with the inferior open.

RESETting a job deletes all of its core, provides it with a single
page of unshared writeable core, closes all the job's channels,
kills all of its inferiors, and re-initializes most of the job's
system variables.  Most notably not cleared out are the job's
translation lists for filenames.

 4. DUMPING
  a. Pure dumping
  b. Impure dumping
 5. STARTING AND STOPPING

An inferior may be started (caused to run) by setting its .USTP
variable to zero.  It will continue with whatever PC it has.
To set the PC, store the desired new PC in the .UPC variable.

An inferior may be stopped by setting the .USTP variable to
nonzero.  The exact value deposited in .USTP will be forgotten
since it corresponds only to a single bit of real storage.
This is how the system stops a job which gets a fatal interrupt.

DDT has another way of stopping a job, which it uses in executing
the ^X command: it turns on bit %PIC.Z of the job's .PIRQC, causing
a fatal ^Z-typed interrupt in that job.
This not only makes the system set the job's .USTP, but causes
DDT's interrupt handler to find out about the stoppage of the
job and be properly faked out.

 6. HANDLING INTERRUPTS

Every job has the ability to enable interrupts on several conditions
(see ITS INTRUP).  Among those conditions is the occurrence of a fatal
error interrupt in an inferior.  This is the mechanism that enables
a job to "return to DDT" deliberately - it simply causes a fatal
interrupt in itself.  This is also how DDT knows when an illegal
instruction is executed by an inferior.

Whenever a job acquires an inferior (by creation or reowning), one
of the job's interrupt bits is assigned to that inferior.  Each
inferior has its own interrupt bit.  There are exactly eight
interrupt bits which can be used for that purpose, which is why a
job can have at most eight inferiors at a time.  Those eight are
all located in the left half of the .IFPIR variable.

The superior should find out which interrupt bit was assigned by reading
the inferior's .INTB variable, in which that bit alone will be 1.

See ITS INTRUP for more details.

The two system calls .VALUE and .BREAK exist solely so that a job can
cause a fatal interrupt to signal its superior.  DDT has standard
interpretations for those instructions;  see .INFO.;DDT ORDER.

 7. DEBUGGING CONTROLS.

These features exist to facilitate debugging.  They work currently on
KA-10's only, though they will be extended to KL-10's eventually.
They are generally used and controlled only by the superior of the
job on which they are acting, to which they are generally transparent.

  a: One-proceed.

If appropriate bits in a job's PC are set, that job will be
able to execute one more instruction and then will get a fatal
%PI1PR interrupt.  This feature is used by DDT's "single step"
command (^N).  Which bits to use depends on the processor type:
for KA's, %PC1PR is the right bit (it is an 18 bit quantity, to
be OR'ed into the flags);  for KL's, %PS1PR is right.  On any
machine, the symbol OIPBIT will be defined in the ITS symbol
table as either %PC1PR,, or %PS1PR,, , whichever is appropriate.

  b: Address-stop (MAR).

The MAR feature makes it possible to trap all references to a
particular address.  When the specified location is referred to
("the MAR is hit"),  the inferior will get a fatal %PIMAR
interrupt, which may or may not allow the instruction that
tripped the MAR to finish.  The MAR is turned off when it is
hit and must be turned on again explicitly or it will stay
off forever.

The MAR is controlled by the .MARA user variable.  Its RH
contains the address to be traced.  Its LH contains the control
code, which is 0 to turn the MAR off, 1 to trap instruction
fetches only, 2 to trap writes only, and 3 to trap all
references.  There is also a variable .MARPC which, after
the MAR is hit, contains the address of the instruction that
hit it.  In addition, the indirect bit will be set on KA's
if the instruction that hit the MAR was completed (on KL's,
the instruction is always aborted).
On KL's, after a MAR, the job's PC (.UPC) will have %PSINH
set, which will inhibit MAR hitting for one instruction
when the job is continued.
The job's PC in .UPC should NOT be used to locate the
instruction that hit the MAR, since if the instruction was
not aborted and was a jump, the PC will be the address
jumped to.  Even if it wasn't a jump, it might have skipped.

  c: .JPC - Last Jump Address.

The user variable .JPC always contains the address of the last
jump instruction executed in the job.  It can be used, for
example, to trace a job backward from the point of failure by
putting in a breakpoint, examining the .JPC when the breakpoint
is hit, and running the program again with the breakpoint now
located at the previous jump, etc.  Unfortunately, subroutine
calls (including user-trapping UUOs) alter the JPC, even though
the information is redundant for them, but returnable UUO's and
interrupts do not.  For that reason, after a returnable UUO
or interrupt a program should always read .JPC before jumping
anywhere, for debugging purposes.  The canonical names UUOJPC
and INTJPC exist for the locations .JPC is saved in.  Also,
error-handling uuos used by the program should be returnable
uuos rather than direct user-trapping uuos, so that the JPC
will be meaningful.  The vectored interrupt mechanism has the
ability to store .JPC automatically on each interrupt (see
ITS INTRUP).

 8. TTY PASSING

For now, see under .ATTY and .DTTY in ITS TTY.

D. SYSTEM JOBS AND WHAT THEY DO

There are two jobs built into the system, that run in exec mode
and perform housekeeping tasks;  they are the system job and
the core job.  There are also various "demon" jobs that exist
at times which, though receiving no special treatment from the
system, may be regarded as part of it in that they provide a
system-wide service.

 1. THE SYSTEM JOB.

This job, whose full name is SYS SYS, provides a great many
independent services;  it is really a timesharing system for
many trusting processes, each of which is controlled by a
single bit in the system variable SUPCOR.  Setting the bit for
a process causes the process to run, and clear the bit.  The
process should never run for very long, or it may tie up the
system by making the services of the other processes
unobtainable.  If a process wishes to run continually, it does
so by setting its bit in SUPCOP.  SUPCOP is or'ed into SUPCOR
every second, so a process whose bit in SUPCOP is set will be
run again that often.  The process is always started the same
way, but it can of course have state variables.

The reasons why a given activity may involve the system job are
1) it may wish to print a message on the system log terminal, or
2) it may need to run in a job (eg, do system calls), but not be
associated with any one job, or 
3) it may need to be able to hang up for short periods of time,
but the need to do it may be noticed at a time when that is
impossible, or
4) it needs to be done once every two minutes or every two hours.
The routines for those "very slow" and "super slow" clocks are in
the system job.

Re-initialising the connection to the IMP is an example of reasons 1
and 2.  Typing "console free" messages is an example of reason 3 - it
involves doing I/O to the terminal, but it isn't done until the last
stage of killing a tree, when waiting of any sort would allow PCLSR'ing,
which would leave things in a screwed-up state.  An example of reason 4
is the detection of core-link files which have not been used for more
than 2 minutes.

A complete list of the system job's functions follows:

  a: Allocating or Deallocating Memory for Job Slots.

Most of the memory occupied by the system is marked as belonging to
the system job.  For that reason, the way more is allocated for user
variable blocks is by having the system job do a .CORE UUO.  This is
somewhat of a historical crock.  Creating a job does not require such
allocation if there are free slots in the memory already allocated. 
However, it may need to.  For that reason, if the system job is hung
up, often jobs cannot be created.

  b: Printing Various Messages on All Terminals.

Sometimes, messages such as "ITS GOING DOWN IN ..." or "ITS BEING
DEBUGGED" are printed on all the terminals in the world.  It is the
system job that prints them on terminals which are free.  Consoles have
them printed by DDT, however.

  c: Checksumming the Constant Areas of the System.

The system job is always checksumming parts of the system and comparing
the checksums with those previously calculated.  This mechanism causes
the clobberage of a word in the code of the system to be detected.  If
only a single word in an area is clobbered, which word it is and the
original contents can be detarmined.  In any case, a message is printed
on the system log terminal when clobberage is found.

  d: Determining the Date and Time.

  e: Detaching Trees.

When a top-level job is halted by a fatal interrupt, it is the system
job which executes the DETACH system call to detach it.  Similarly, it
is the system job which detaches trees controlled by TV terminals when
the TV system crashes, and trees controlled by dialup lines whose
connections are broken (only when the hardware can detect that).

  f: Depositing  in the System.

When a job deposits in the system using .SETLOC or .IFSET, the system
job is informed so that it can update its checksums and avoid a system
clobbered" message.  It also makes the change.

This used to be a great screw, in that if the system job were hung, it
could not be fixed by depositing in the system.  Now, .SETLOC will do
the work itself without calling the system job, if the system job
appears to be hung.

  g: Printing "Console-free" Messages.

When a terminal ceases to be in use, the system job is signalled to look
at all terminals and print console-free messages on all those which have
recently stopped being in use.

  h: Logging Out.

The final stages of killing a job must be run by some other job.  When a
top-level job is being killed, it does some of the work itself (kills
its inferiors and closes its channels).  That is to make sure the
system job never hangs up trying to do it.  The rest of the work is
then done by the system job, which can afford to wait for short peiods
of time when the job is almost killed.

  i: Reinitialising the NCP.

When the connection to the ARPA network goes down, the system job gives
interrupts to all the jobs using the network, and also checks every so
often whether the network is useable again.

  j: Printing of Various Messages on the System Log Terminal.

Events which cause messages on the log terminal include logging in,
logging out, writing on a directory whose name starts with "SYS",
garbage-collecting a disk directory, creating a disk directory,
gunning, parity errors, NXM errors.

  l: Spooling the LPT.

On AIKA and ML, the system job checks periodically for spooled files
and prints them.

  m: Starting Other Demons.

On DM, the system job checks for any domon programs which have been
signaled.  If there are any, it loads them into newly created jobs
and strats them.

  n: Reinitialising the TV System, or Noticeing that it is Down.

 2. THE CORE JOB.

This job, whose full name is CORE JOB, allocates core to jobs that
request it, and also frees up memory for use as user variable blocks,
which have to be allocated consecutively, by relocating the old
contents.  Before there was pageing, the core job used to do shuffling.

 3. DEMON JOBS.

  a: The Comsat.

This demon, always named after some spacecraft or rocket, is responsible
for handling mail.  Requests to send mail are placed in the .MAIL.
directory, and are eventually processed by the demon.  The demon is
necessary because it may not be possible to send mail to other machines
right away, and in any case the user should not have to wait the time
it takes.  It also provides other services such as forwarding.

  b: NAMDRG.

This demon maintains the list of logged in users which appears on all
free TV consoles.  It also updates a file saying when every user
logged out last.  It exists on AIKA only.

  c: PFTHMG DRAGON.

This demon updates the logout times file and keeps track of each user's
total CPU time.  This demon originated on ML, but has run on all ITS
machines at one time or another.

